/*
 * Niiuzu
 * Copyright (C) 2011  Thierry Nowak
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.niiuzu.client.screen.authentification.login;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.inject.Inject;
import com.mvp4g.client.annotation.Presenter;
import com.mvp4g.client.presenter.LazyPresenter;
import com.niiuzu.client.eventbus.AuthentificationEventBus;
import com.niiuzu.client.i18n.AuthentificationMessages;
import com.niiuzu.client.util.ClientContextFactory;
import com.niiuzu.client.util.LoadingTicket;
import com.niiuzu.client.util.SessionClient;
import com.niiuzu.client.util.callback.AbstractCallback;
import com.niiuzu.client.util.cookie.CookieManager;
import com.niiuzu.client.util.cookie.CookieName;
import com.niiuzu.shared.model.UserLogInResult;
import com.niiuzu.shared.rpc.UserServiceAsync;

/**
 * Presenter du formulaire de connexion de l'utilisateur.
 */
@Presenter(view = LogInViewImpl.class)
public class LogInPresenter extends
		LazyPresenter<LogInView, AuthentificationEventBus> {

	@Inject
	private UserServiceAsync userService;

	private AuthentificationMessages authentificationMessages = GWT
			.create(AuthentificationMessages.class);

	private ClickHandler closeClickHandler;
	private ClickHandler validateClickHandler;
	private ClickHandler lostPasswordClickHandler;

	@Override
	public void bindView() {
		super.bindView();

		validateClickHandler = new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				launchUserLogInValidation();
			}
		};
		view.getValidationHasClickHandlers().addClickHandler(
				validateClickHandler);

		closeClickHandler = new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				view.hidePopup();
			}
		};
		view.getCloseButtonHasClickHandlers()
				.addClickHandler(closeClickHandler);
		view.getCancelHasClickHandlers().addClickHandler(closeClickHandler);

		lostPasswordClickHandler = new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				eventBus.userPasswordHasBeenLost();
			}
		};
		view.getLostPasswordHasClickHandlers().addClickHandler(
				lostPasswordClickHandler);
	}

	/**
	 * Lance la validation du formulaire de connexion.
	 */
	private void launchUserLogInValidation() {

		String mail = view.getMailHasValue().getValue();
		String password = view.getPasswordHasValue().getValue();

		if ("".equals(mail)) {
			eventBus.businessErrorOccurred(authentificationMessages
					.errorMissingMailValue());
		} else if ("".equals(password)) {
			eventBus.businessErrorOccurred(authentificationMessages
					.errorMissingPasswordValue());
		} else {

			String message = authentificationMessages.validatingCredentials();
			final LoadingTicket ticket = LoadingTicket.Factory.createTicket(
					getClass(), message);
			eventBus.loadingStarted(ticket);

			Boolean rememberUserRaw = view.getRememberUserHasValue().getValue();
			boolean rememberUser = Boolean.TRUE.equals(rememberUserRaw);

			userService.logUserInFromCredentials(mail, password, rememberUser,
					ClientContextFactory.get(),
					new AbstractCallback<UserLogInResult>(eventBus, ticket) {
						@Override
						public void onSuccess(UserLogInResult result) {
							retrieveUser(result, ticket);
						}
					});
		}
	}

	/**
	 * Réception d'une demande d'affichage du formulaire.
	 * 
	 * @see AuthentificationEventBus#logInFormWanted()
	 */
	public void onLogInFormWanted() {

		view.getMailHasValue().setValue("");
		view.getPasswordHasValue().setValue("");
		view.getRememberUserHasValue().setValue(false);

		view.showPopup();

		view.focusMailField();
	}

	/**
	 * Récupération du résultat de l'appel au service et passage aux étapes
	 * suivantes.
	 */
	void retrieveUser(UserLogInResult userLogInResult, LoadingTicket ticket) {

		view.getPasswordHasValue().setValue("");

		// Aucune correspondance dans les utilisateurs.
		if (userLogInResult == null) {
			eventBus.loadingFinished(ticket);
			eventBus.businessErrorOccurred(authentificationMessages
					.errorUserNotFound());
		} else {

			// Sauvegarde de la référence à l'utilisateur si celle-ci existe
			String userReference = userLogInResult.getCryptedUserReference();
			if (userReference != null) {
				CookieManager cookieManager = getCookieManager();
				cookieManager.setCookieValue(
						CookieName.REMEMBER_USER_REFERENCE, userReference,
						CookieManager.DELTA_ONE_MONTH);
			}

			// Sauvegarde l'instance de l'utilisateur dans la session
			SessionClient.getInstance().setUser(userLogInResult.getUser());

			view.hidePopup();
			eventBus.userLoggedIn(ticket);
		}
	}

	/**
	 * Comportement déclenché suite au clic sur les boutons de fermeture de la
	 * popup.
	 */
	public ClickHandler getCloseClickHandler() {
		return closeClickHandler;
	}

	/**
	 * Comportement déclenché suite au clic sur le bouton de validation du
	 * formulaire.
	 */
	public ClickHandler getValidateClickHandler() {
		return validateClickHandler;
	}

	/**
	 * Comportement déclenché suite au clic sur le lien du mot de passe perdu.
	 */
	ClickHandler getLostPasswordClickHandler() {
		return lostPasswordClickHandler;
	}

	/**
	 * Récupère une instance de {@link CookieManager}.
	 */
	public CookieManager getCookieManager() {
		if (mockedCookieManager != null) {
			return mockedCookieManager;
		}
		return new CookieManager();
	}

	/* ********************************************************************** */
	/* ********************************************************************** */
	/* ********************************************************************** */

	private CookieManager mockedCookieManager;

	/**
	 * JUnit - Définit un mock pour {@link UserServiceAsync}.
	 */
	void setMockedUserService(UserServiceAsync mockedUserService) {
		this.userService = mockedUserService;
	}

	/**
	 * JUnit - Définit un mock pour {@link AuthentificationMessages}.
	 */
	void setMockedAuthentificationMessages(
			AuthentificationMessages mockedAuthentificationMessages) {
		this.authentificationMessages = mockedAuthentificationMessages;
	}

	/**
	 * JUnit - Définit un mock pour {@link CookieManager}.
	 */
	void setMockedCookieManager(CookieManager mockedCookieManager) {
		this.mockedCookieManager = mockedCookieManager;
	}
}
